package cn.com.shopec.erp.system.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import cn.com.shopec.erp.base.vo.SupplierVo;
import cn.com.shopec.erp.common.utils.StringUtil;
import cn.com.shopec.erp.system.common.MenuUtils;
import cn.com.shopec.erp.system.constant.SystemConstant;
import cn.com.shopec.erp.system.dao.IAccessDao;
import cn.com.shopec.erp.system.dao.IMenuDao;
import cn.com.shopec.erp.system.dao.IRoleDao;
import cn.com.shopec.erp.system.dao.IUserDao;
import cn.com.shopec.erp.system.entity.Access;
import cn.com.shopec.erp.system.entity.Menu;
import cn.com.shopec.erp.system.entity.Role;
import cn.com.shopec.erp.system.entity.User;
import cn.com.shopec.erp.system.service.IAccessService;
import cn.com.shopec.erp.system.vo.AccessVo;
import cn.com.shopec.erp.system.vo.UserVo;

/**
 * 
 * @ClassName AccessServiceImpl
 * @Description 权限Service实现
 * @author chengui
 * @date 2013-5-30 上午11:03:48
 */
@Service
public class AccessServiceImpl implements IAccessService {
	
	@Resource private IUserDao userDao;
	@Resource private IAccessDao accessDao;
	@Resource private IMenuDao menuDao;
	@Resource private IRoleDao roleDao;

	@Override
	public void addOrModifyMenu(AccessVo accessVo) throws Exception {
		if (null != accessVo) {
			Menu menu = null;
			if (StringUtil.isExist(accessVo.getId()) && !StringUtil.isExist(accessVo.getParentId())) {
				menu = menuDao.getById(accessVo.getId());
				setMenuAttr(menu, accessVo);
				menuDao.save(menu);
			} else {
				Access access = new Access();
				access.setAccessName(accessVo.getMenuName());
				access.setAccessType(accessVo.getAccessType());
				accessDao.save(access);
				
				menu = new Menu();
				if (StringUtil.isExist(accessVo.getParentId())) {
					Menu pMenu = menuDao.getById(accessVo.getParentId());
					menu.setStructure(MenuUtils.getMenuStructure(pMenu));
					menu.setLevel(MenuUtils.getMenuLevel(pMenu));
					menu.setMenu(pMenu);
				} else {
					DetachedCriteria criteria = menuDao.createCriteria();
					criteria.add(Restrictions.isNull("menu"));
					criteria.add(Restrictions.eq("deleteFlag", SystemConstant.DELETE_FLAG_1));
					int rootSize = menuDao.getCountByCriteria(criteria);
					menu.setStructure(MenuUtils.getMenuStructure(rootSize));
					menu.setMenu(null);
				}
				menu.setAccess(access);
				setMenuAttr(menu, accessVo);
				menuDao.save(menu);
			}
		}
	}
	
	/**
	 * 
	 * @MethodName setMenuAttr
	 * @Description 设置Menu的公用属性
	 * @author chengui
	 * @date 2013-6-1 上午11:22:57
	 * @param menu
	 * @param accessVo
	 */
	private void setMenuAttr(Menu menu, AccessVo accessVo) throws Exception {
		menu.setMenuName(accessVo.getMenuName());
		menu.setMenuUrl(accessVo.getMenuUrl());
		menu.setMenuSort(accessVo.getMenuSort());
		menu.setMenuType(accessVo.getMenuType());
		menu.setRemark(accessVo.getRemark());
	}

	@Override
	public List<AccessVo> getMenuVos(AccessVo accessVo, boolean onceLoad, int menuType) throws Exception {
		List<Menu> menus = getMenus(accessVo, menuType);
		List<AccessVo> accessVos = null;
		if (onceLoad) {
			accessVos = new ArrayList<AccessVo>();
			if (null != menus && menus.size() > 0) {
				AccessVo aVo = null;
				for (Menu menu : menus) {
					if (menu.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
						aVo = new AccessVo();
						aVo.setRoleId(accessVo.getRoleId());
						getChildMenus(menu, aVo);
						accessVos.add(aVo);
					}
				}
			}
		} else {
			accessVos = convertToAccessVos(menus);
		}
		return accessVos;
	}
	
	/**
	 * 
	 * @MethodName convertToAccessVo
	 * @Description 单个菜单转换成Vo
	 * @author chengui
	 * @date 2013-6-3 下午4:13:26
	 * @param menu
	 * @param accessVo
	 * @throws Exception
	 */
	private void convertToAccessVo(Menu menu, AccessVo accessVo) throws Exception {
		if (menu != null) {
			BeanUtils.copyProperties(menu, accessVo);
			accessVo.setText(menu.getMenuName());
			if (StringUtil.isExist(accessVo.getRoleId())) {
				Hibernate.initialize(menu.getAccess());
				String accessId = menu.getAccess().getId();
				Query query = accessDao.createSQLQuery("select * from tbl_scm_role_access t where t.role_id=:roleId and t.access_id=:accessId");
				query.setParameter("roleId", accessVo.getRoleId());
				query.setParameter("accessId", accessId);
				int count = query.list().size();
				if (count > 0) {
					accessVo.setIschecked(true);
				}
			}
			Hibernate.initialize(menu.getMenus());
			List<Menu> lMenu = new ArrayList<Menu>();
			Set<Menu> ms = menu.getMenus();
			if (null != ms && ms.size() > 0) {
				for (Menu m : ms) {
					if (m.getDeleteFlag() != SystemConstant.DELETE_FLAG_0) {
						lMenu.add(m);
					}
				}
			}
			if (null == lMenu || lMenu.size() == 0) {
				accessVo.setChildren(null);
			}
		}
	}
	
	/**
	 * 
	 * @MethodName getChildMenus
	 * @Description 获得子菜单
	 * @author chengui
	 * @date 2013-6-3 下午4:12:44
	 * @param menu
	 * @param accessVo
	 * @throws Exception
	 */
	private void getChildMenus(Menu menu, AccessVo accessVo) throws Exception {
		Hibernate.initialize(menu.getMenus());
		Set<Menu> childMenus = menu.getMenus();
		List<Menu> lChildMenus = new ArrayList<Menu>();
		convertToAccessVo(menu, accessVo);
		if (null != childMenus && childMenus.size() > 0) {
			for (Menu m : childMenus) {
				if (m.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
					lChildMenus.add(m);
				}
			}
			if (null != lChildMenus && lChildMenus.size() > 0) {
				Collections.sort(lChildMenus, new Comparator<Menu>() {

					@Override
					public int compare(Menu o1, Menu o2) {
						return o1.getMenuSort() - o2.getMenuSort();
					}
					
				});
				accessVo.setChildren(convertToAccessVos(lChildMenus));
			}
			for (int i=0; i<lChildMenus.size(); i++) {
				Menu m = lChildMenus.get(i);
				AccessVo aVo = accessVo.getChildren().get(i);
				aVo.setRoleId(accessVo.getRoleId());
				getChildMenus(m, aVo);
			}
		}
	}

	/**
	 * 
	 * @MethodName convertToAccessVos
	 * @Description 将菜单焦点转换成权限Vo集合
	 * @author chengui
	 * @date 2013-5-31 下午5:05:48
	 * @param menus
	 * @return
	 * @throws Exception
	 */
	private List<AccessVo> convertToAccessVos(List<Menu> menus) throws Exception {
		List<AccessVo> accessVos = new ArrayList<AccessVo>();
		if (null != menus && menus.size() > 0) {
			AccessVo accessVo = null;
			for (Menu menu : menus) {
				if (menu.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
					accessVo = new AccessVo();
					convertToAccessVo(menu, accessVo);
					
					accessVos.add(accessVo);
				}
			}
		}
		return accessVos;
	}

	/**
	 * 
	 * @MethodName getMenus
	 * @Description 获得菜单集合
	 * @author chengui
	 * @date 2013-5-31 下午5:05:04
	 * @param accessVo
	 * @return List<Menu>
	 * @throws Exception
	 */
	private List<Menu> getMenus(AccessVo accessVo, int menuType) throws Exception {
		DetachedCriteria criteria = menuDao.createCriteria();
		if (null != accessVo) {
			if (null == accessVo.getId()) {
				criteria.add(Restrictions.isNull("menu"));
			} else {
				criteria.createAlias("menu", "menu");
				criteria.add(Restrictions.eq("menu.id", accessVo.getId()));
			}
		}
		if (menuType == SystemConstant.MENU_TYPE_1) {
			criteria.add(Restrictions.eq("menuType", SystemConstant.MENU_TYPE_1));
		} else if (menuType == SystemConstant.MENU_TYPE_2) {
			criteria.add(Restrictions.eq("menuType", SystemConstant.MENU_TYPE_2));
		}
		criteria.addOrder(Order.asc("menuSort"));
		criteria.add(Restrictions.eq("deleteFlag", SystemConstant.DELETE_FLAG_1));
		List<Menu> menus = menuDao.findByCriteria(criteria);
		return menus;
	}

	@Override
	public void deleteMenuNode(AccessVo accessVo) throws Exception {
		Menu menu = menuDao.getById(accessVo.getId());
		menu.setDeleteFlag(SystemConstant.DELETE_FLAG_0);
		menuDao.update(menu);
	}

	@Override
	public List<AccessVo> loadOwnTree(UserVo userVo) throws Exception {
		User user = userDao.getById(userVo.getId());
		List<AccessVo> accessVos = null;
		if (user.getUserNature() == SystemConstant.USER_NATURE_2) {
			accessVos = getMenuVos(new AccessVo(), true, SystemConstant.MENU_TYPE_1);
		} else {
			accessVos = new ArrayList<AccessVo>();
			Hibernate.initialize(user.getRoles());
			Set<Role> roles = user.getRoles();
			Set<Menu> menus = new HashSet<Menu>();
			if (null != roles && roles.size() > 0) {
				for (Role role : roles) {
					fillMenus(role, menus);
				}
			}
			fillAccessVos(menus, accessVos);
		}
		return accessVos;
	}
	
	/**
	 * 
	 * @MethodName getAccessedChildMenus
	 * @Description 获得有权限的子菜单
	 * @author chengui
	 * @date 2013-6-5 下午2:32:51
	 * @param menu
	 * @param accessVo
	 * @throws Exception
	 */
	private void getAccessedChildMenus(Menu menu, AccessVo accessVo, Set<Menu> menus) throws Exception {
		List<Menu> lChildMenus = new ArrayList<Menu>();
		convertToAccessVo(menu, accessVo);
		if (null != menus && menus.size() > 0) {
			for (Menu m : menus) {
				if (m.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
					if (null != m.getMenu()) {
						if (m.getMenu().getId().equals(menu.getId())) {
							lChildMenus.add(m);
						}
					}
				}
			}
			if (null != lChildMenus && lChildMenus.size() > 0) {
				Collections.sort(lChildMenus, new Comparator<Menu>() {

					@Override
					public int compare(Menu o1, Menu o2) {
						return o1.getMenuSort() - o2.getMenuSort();
					}
					
				});
				accessVo.setChildren(convertToAccessVos(lChildMenus));
			}
			for (int i=0; i<lChildMenus.size(); i++) {
				Menu m = lChildMenus.get(i);
				AccessVo aVo = accessVo.getChildren().get(i);
				getAccessedChildMenus(m, aVo, menus);
			}
		}
	}

	@Override
	public List<AccessVo> loadOwnTree(SupplierVo suppVo) throws Exception {
		List<AccessVo> accessVos = new ArrayList<AccessVo>();
		Set<Menu> menus = new HashSet<Menu>();
		if (StringUtil.isExist(suppVo.getAccountsType()) && suppVo.getAccountsType().equals(SystemConstant.SUPPLIER_ACCOUNT_1)) {
			Role role = roleDao.findUniqueBy("roleCode", SystemConstant.PURCHASE_SUPPLIER);
			if (null != role && role.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
				fillMenus(role, menus);
				fillAccessVos(menus, accessVos);
			}
		} else if (StringUtil.isExist(suppVo.getAccountsType()) && suppVo.getAccountsType().equals(SystemConstant.SUPPLIER_ACCOUNT_2)) {
			Role role = roleDao.findUniqueBy("roleCode", SystemConstant.CONSIGNMENT_SUPPLIER);
			if (null != role && role.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
				fillMenus(role, menus);
				fillAccessVos(menus, accessVos);
			}
		} else if (StringUtil.isExist(suppVo.getAccountsType()) && suppVo.getAccountsType().equals(SystemConstant.SUPPLIER_ACCOUNT_3)) {
			DetachedCriteria criteria = roleDao.createCriteria();
			criteria.add(Restrictions.in("roleCode", new String[]{SystemConstant.PURCHASE_SUPPLIER, SystemConstant.CONSIGNMENT_SUPPLIER}));
			criteria.add(Restrictions.eq("deleteFlag", SystemConstant.DELETE_FLAG_1));
			List<Role> roles = roleDao.findByCriteria(criteria);
			if (null != roles && roles.size() > 0) {
				for (Role role : roles) {
					fillMenus(role, menus);
				}
				fillAccessVos(menus, accessVos);
			}
		}
		return accessVos;
	}
	
	/**
	 * 
	 * @MethodName fillAccessVos
	 * @Description 填充菜单Vo
	 * @author chengui
	 * @date 2013-6-9 下午5:05:23
	 * @param menus
	 * @param accessVos
	 */
	private void fillAccessVos(Set<Menu> menus, List<AccessVo> accessVos) throws Exception {
		if (menus.size() > 0) {
			List<Menu> ms = new ArrayList<Menu>();
			for (Menu menu : menus) {
				if (null == menu.getMenu()) {
					ms.add(menu);
				}
			}
			if (ms.size() > 0) {
				AccessVo aVo = null;
				for (Menu menu : ms) {
					if (menu.getDeleteFlag() == SystemConstant.DELETE_FLAG_1) {
						aVo = new AccessVo();
						getAccessedChildMenus(menu, aVo, menus);
						accessVos.add(aVo);
					}
				}
			}
		}
	}

	/**
	 * 
	 * @MethodName fillMenus
	 * @Description 填充菜单
	 * @author chengui
	 * @date 2013-6-9 下午4:58:49
	 * @param role
	 * @param menus
	 */
	private void fillMenus(Role role, Set<Menu> menus) throws Exception {
		Menu menu = null;
		Hibernate.initialize(role.getAccesses());
		Set<Access> accesses = role.getAccesses();
		if (null != accesses && accesses.size() > 0) {
			for (Access access : accesses) {
				if (access.getDeleteFlag() != SystemConstant.DELETE_FLAG_0) {
					Hibernate.initialize(access.getMenu());
					menu = access.getMenu();
					if (null != menu && menu.getDeleteFlag() != SystemConstant.DELETE_FLAG_0) {
						menus.add(menu);
					}
				}
			}
		}
	}
	
}
